package com.salesmanager.web.admin.controller.orders;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.impl.cookie.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.salesmanager.core.business.catalog.product.model.Product;
import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
import com.salesmanager.core.business.catalog.product.model.description.ProductDescription;
import com.salesmanager.core.business.catalog.product.model.price.ProductPrice;
import com.salesmanager.core.business.catalog.product.service.PricingService;
import com.salesmanager.core.business.catalog.product.service.ProductService;
import com.salesmanager.core.business.catalog.product.service.availability.ProductAvailabilityService;
import com.salesmanager.core.business.customer.model.Customer;
import com.salesmanager.core.business.customer.service.CustomerService;
import com.salesmanager.core.business.generic.exception.ServiceException;
import com.salesmanager.core.business.merchant.model.MerchantStore;
import com.salesmanager.core.business.order.model.Order;
import com.salesmanager.core.business.order.model.OrderTotal;
import com.salesmanager.core.business.order.model.OrderType;
import com.salesmanager.core.business.order.model.orderproduct.OrderProduct;
import com.salesmanager.core.business.order.model.orderproduct.OrderProductDownload;
import com.salesmanager.core.business.order.model.orderstatus.OrderStatus;
import com.salesmanager.core.business.order.model.orderstatus.OrderStatusHistory;
import com.salesmanager.core.business.order.service.OrderService;
import com.salesmanager.core.business.order.service.orderproduct.OrderProductDownloadService;
import com.salesmanager.core.business.payments.model.PaymentStatus;
import com.salesmanager.core.business.payments.model.PaymentType;
import com.salesmanager.core.business.payments.model.Transaction;
import com.salesmanager.core.business.payments.service.PaymentService;
import com.salesmanager.core.business.payments.service.TransactionService;
import com.salesmanager.core.business.reference.country.model.Country;
import com.salesmanager.core.business.reference.country.service.CountryService;
import com.salesmanager.core.business.reference.language.model.Language;
import com.salesmanager.core.business.reference.zone.model.Zone;
import com.salesmanager.core.business.reference.zone.service.ZoneService;
import com.salesmanager.core.business.system.service.EmailService;
import com.salesmanager.core.modules.email.Email;
import com.salesmanager.core.utils.ajax.AjaxResponse;
import com.salesmanager.web.admin.controller.ControllerConstants;
import com.salesmanager.web.admin.entity.web.Menu;
import com.salesmanager.web.constants.Constants;
import com.salesmanager.web.constants.EmailConstants;
import com.salesmanager.web.shop.controller.order.facade.OrderFacade;
import com.salesmanager.web.shop.controller.order.facade.OrderFacadeImpl;
import com.salesmanager.web.utils.DateUtil;
import com.salesmanager.web.utils.EmailUtils;
import com.salesmanager.web.utils.LabelUtils;
import com.salesmanager.web.utils.LocaleUtils;

/**
 * Manage order details
 * @author Carl Samson
 *
 */
@Controller
public class OrderControler {

public static final String COUNTRY_CODE_DEFAULT = "VN";	
private static final Logger LOGGER = LoggerFactory.getLogger(OrderControler.class);

//String email_regEx = "\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}\\b";
private final static Pattern PATTERN = Pattern.compile("\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}\\b");
	
	@Autowired
	private LabelUtils messages;
	
	@Autowired
	private OrderService orderService;
	
	@Autowired
	CountryService countryService;
	
	@Autowired
	ZoneService zoneService;
	
	@Autowired
	PaymentService paymentService;
	
	@Autowired
	CustomerService customerService;
	
	@Autowired
	PricingService pricingService;
	
	@Autowired
	TransactionService transactionService;
	
	@Autowired
	EmailService emailService;
	
	@Autowired
	ProductService productService;
	
	@Autowired
	OrderProductDownloadService orderProdctDownloadService;
	
	@Autowired
	protected ProductAvailabilityService productAvailabilityService;
	
	private final static String ORDER_STATUS_TMPL = "email_template_order_status.ftl";
	public final static SimpleDateFormat VN_DATE_FORMAT = new SimpleDateFormat("dd-MM-yyyy");

	@PreAuthorize("hasRole('ORDER')")
	@RequestMapping(value="/admin/orders/editOrder.html", method=RequestMethod.GET)
	public String displayOrderEdit(@RequestParam("id") long orderId, Model model, HttpServletRequest request, HttpServletResponse response) throws Exception {

		return displayOrder(orderId,model,request,response);

	}

	@PreAuthorize("hasRole('ORDER')")
	private String displayOrder(Long orderId, Model model, HttpServletRequest request, HttpServletResponse response) throws Exception {

		//display menu
		setMenu(model,request);
		   
		com.salesmanager.web.admin.entity.orders.Order order = new com.salesmanager.web.admin.entity.orders.Order();
		Language language = (Language)request.getAttribute("LANGUAGE");
		List<Country> countries = countryService.getCountries(language);
		if(orderId!=null && orderId!=0) {		//edit mode		
			MerchantStore store = (MerchantStore)request.getAttribute(Constants.ADMIN_STORE);
			
			Set<OrderProduct> orderProducts = null;
			Set<OrderTotal> orderTotal = null;
			Set<OrderStatusHistory> orderHistory = null;
		
			Order dbOrder = orderService.getById(orderId);

			if(dbOrder==null) {
				return "redirect:/admin/orders/list.html";
			}
			
			
			if(dbOrder.getMerchant().getId().intValue()!=store.getId().intValue()) {
				return "redirect:/admin/orders/list.html";
			}			
			
			order.setId( orderId );
		
			if( dbOrder.getDatePurchased() !=null ){
				order.setDatePurchased(VN_DATE_FORMAT.format(dbOrder.getDatePurchased()));
			}
			
			Long customerId = dbOrder.getCustomerId();
			
			if(customerId!=null && customerId>0) {
				try {
					Customer customer = customerService.getById(customerId);
					if(customer!=null) {
						model.addAttribute("customer",customer);
					}
				} catch(Exception e) {
					LOGGER.error("Error while getting customer for customerId " + customerId, e);
				}
			
			}
			
			order.setOrder( dbOrder );
			order.setBilling( dbOrder.getBilling() );
			order.setDelivery(dbOrder.getDelivery() );
			
			
			orderProducts = dbOrder.getOrderProducts();
			orderTotal = dbOrder.getOrderTotal();
			orderHistory = dbOrder.getOrderHistory();
			
			//get capturable
//			if(dbOrder.getPaymentType().name() != PaymentType.MONEYORDER.name()) {
//				Transaction capturableTransaction = transactionService.getCapturableTransaction(dbOrder);
//				if(capturableTransaction!=null) {
//					model.addAttribute("capturableTransaction",capturableTransaction);
//				}
//			}
			
			
			//get refundable
//			if(dbOrder.getPaymentType().name() != PaymentType.MONEYORDER.name()) {
//				Transaction refundableTransaction = transactionService.getRefundableTransaction(dbOrder);
//				if(refundableTransaction!=null) {
//						model.addAttribute("capturableTransaction",null);//remove capturable
//						model.addAttribute("refundableTransaction",refundableTransaction);
//				}
//			}

			
			List<OrderProductDownload> orderProductDownloads = orderProdctDownloadService.getByOrderId(order.getId());
			if(CollectionUtils.isNotEmpty(orderProductDownloads)) {
				model.addAttribute("downloads",orderProductDownloads);
			}
			
		}	
		
		model.addAttribute("orderStatusList", Arrays.asList(OrderStatus.values()));
		model.addAttribute("paymentStatusList", Arrays.asList(PaymentStatus.values()));
		model.addAttribute("countries", countries);
		model.addAttribute("order",order);
		return  ControllerConstants.Tiles.Order.ordersEdit;
	}
	

	@PreAuthorize("hasRole('ORDER')")
	@RequestMapping(value="/admin/orders/save.html", method=RequestMethod.POST)
	public String saveOrder(@Valid @ModelAttribute("order") com.salesmanager.web.admin.entity.orders.Order entityOrder, BindingResult result, Model model, HttpServletRequest request, Locale locale) throws Exception {
		
		String email_regEx = "\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}\\b";
		Pattern pattern = Pattern.compile(email_regEx);
		
		Language language = (Language)request.getAttribute("LANGUAGE");
		List<Country> countries = countryService.getCountries(language);
		model.addAttribute("countries", countries);
		
		MerchantStore store = (MerchantStore)request.getAttribute(Constants.ADMIN_STORE);
		
		//set the id if fails
		entityOrder.setId(entityOrder.getOrder().getId());
		
		model.addAttribute("order", entityOrder);
		
		Set<OrderProduct> orderProducts = new HashSet<OrderProduct>();
		Set<OrderTotal> orderTotal = new HashSet<OrderTotal>();
		Set<OrderStatusHistory> orderHistory = new HashSet<OrderStatusHistory>();
		
		Date date = new Date();
		if(!StringUtils.isBlank(entityOrder.getDatePurchased() ) ){
			try {
				date = VN_DATE_FORMAT.parse(entityOrder.getDatePurchased());
			} catch (Exception e) {
				ObjectError error = new ObjectError("datePurchased",messages.getMessage("message.invalid.date", locale));
				result.addError(error);
			}
			
		} else{
			date = null;
		}
		 

		if(!StringUtils.isBlank(entityOrder.getOrder().getCustomerEmailAddress() ) ){
			 java.util.regex.Matcher matcher = pattern.matcher(entityOrder.getOrder().getCustomerEmailAddress());
			 
			 if(!matcher.find()) {
				ObjectError error = new ObjectError("customerEmailAddress",messages.getMessage("Email.order.customerEmailAddress", locale));
				result.addError(error);
			 }
		}else{
			ObjectError error = new ObjectError("customerEmailAddress",messages.getMessage("NotEmpty.order.customerEmailAddress", locale));
			result.addError(error);
		}

		 
		if( StringUtils.isBlank(entityOrder.getOrder().getBilling().getFirstName() ) ){
			 ObjectError error = new ObjectError("billingFirstName", messages.getMessage("NotEmpty.order.billingFirstName", locale));
			 result.addError(error);
		}
		
		if( StringUtils.isBlank(entityOrder.getOrder().getBilling().getFirstName() ) ){
			 ObjectError error = new ObjectError("billingLastName", messages.getMessage("NotEmpty.order.billingLastName", locale));
			 result.addError(error);
		}
		
		/*
		if(OrderType.ORDER.equals(entityOrder.getOrder().getOrderType())){
			if( StringUtils.isBlank(entityOrder.getOrder().getBilling().getAddress() ) ){
				 ObjectError error = new ObjectError("billingAddress", messages.getMessage("NotEmpty.order.billingStreetAddress", locale));
				 result.addError(error);
			}
			 
			if( StringUtils.isBlank(entityOrder.getOrder().getBilling().getCity() ) ){
				 ObjectError error = new ObjectError("billingCity",messages.getMessage("NotEmpty.order.billingCity", locale));
				 result.addError(error);
			}
			 
			if( entityOrder.getOrder().getBilling().getZone()==null){
				if( StringUtils.isBlank(entityOrder.getOrder().getBilling().getState())){
					 ObjectError error = new ObjectError("billingState",messages.getMessage("NotEmpty.order.billingState", locale));
					 result.addError(error);
				}
			}
			 
			if( StringUtils.isBlank(entityOrder.getOrder().getBilling().getPostalCode() ) ){
				 ObjectError error = new ObjectError("billingPostalCode", messages.getMessage("NotEmpty.order.billingPostCode", locale));
				 result.addError(error);
			}
		}
		*/
		
		com.salesmanager.core.business.order.model.Order newOrder = orderService.getById(entityOrder.getOrder().getId() );
		
		
		//get capturable
		if(newOrder.getPaymentType().name() != PaymentType.MONEYORDER.name()) {
			Transaction capturableTransaction = transactionService.getCapturableTransaction(newOrder);
			if(capturableTransaction!=null) {
				model.addAttribute("capturableTransaction",capturableTransaction);
			}
		}
		
		
		//get refundable
		if(newOrder.getPaymentType().name() != PaymentType.MONEYORDER.name()) {
			Transaction refundableTransaction = transactionService.getRefundableTransaction(newOrder);
			if(refundableTransaction!=null) {
					model.addAttribute("capturableTransaction",null);//remove capturable
					model.addAttribute("refundableTransaction",refundableTransaction);
			}
		}
	
	
		if (result.hasErrors()) {
			//  somehow we lose data, so reset Order detail info.
			entityOrder.getOrder().setOrderProducts( orderProducts);
			entityOrder.getOrder().setOrderTotal(orderTotal);
			entityOrder.getOrder().setOrderHistory(orderHistory);
			model.addAttribute("orderStatusList", Arrays.asList(OrderStatus.values()));
			model.addAttribute("paymentStatusList", Arrays.asList(PaymentStatus.values()));
			return ControllerConstants.Tiles.Order.ordersEdit;
		/*	"admin-orders-edit";  */
		}
		
		OrderStatusHistory orderStatusHistory = new OrderStatusHistory();

		
		Country deliveryCountry = countryService.getByCode(COUNTRY_CODE_DEFAULT); 
		Country billingCountry  = countryService.getByCode(COUNTRY_CODE_DEFAULT);
		Zone billingZone = null;
		Zone deliveryZone = null;
		if(entityOrder.getOrder().getBilling().getZone()!=null) {
			billingZone = zoneService.getByCode(entityOrder.getOrder().getBilling().getZone().getCode());
		}
		
		if(entityOrder.getOrder().getDelivery().getZone()!=null) {
			deliveryZone = zoneService.getByCode(entityOrder.getOrder().getDelivery().getZone().getCode());
		}

		newOrder.setCustomerEmailAddress(entityOrder.getOrder().getCustomerEmailAddress() );
		OrderStatus currentStatus = newOrder.getStatus();
		OrderStatus newStatus = entityOrder.getOrder().getStatus();
		
		int action = OrderUtils.quantityAction(currentStatus, newStatus, newOrder.getOrderType());
		if (action != OrderUtils.NOACTION_QUANTITY){
			if(OrderType.ORDER.equals(newOrder.getOrderType())){
				updateQuantity(newOrder.getOrderProducts(), action, language);
			} else {
				updateImportQuantity(newOrder.getOrderProducts(), action, language);
			}
		}
		
		newOrder.setStatus(newStatus);		
		newOrder.setPaymentStatus(entityOrder.getOrder().getPaymentStatus());
		
		newOrder.setDatePurchased(date);
		newOrder.setLastModified( new Date() );
		
		if(!StringUtils.isBlank(entityOrder.getOrderHistoryComment() ) ) {
			orderStatusHistory.setComments( entityOrder.getOrderHistoryComment() );
			orderStatusHistory.setCustomerNotified(1);
			orderStatusHistory.setStatus(entityOrder.getOrder().getStatus());
			orderStatusHistory.setDateAdded(new Date() );
			orderStatusHistory.setOrder(newOrder);
			newOrder.getOrderHistory().add( orderStatusHistory );
			entityOrder.setOrderHistoryComment( "" );
		}		
		
		newOrder.setDelivery( entityOrder.getOrder().getDelivery() );
		newOrder.setBilling( entityOrder.getOrder().getBilling() );
		
		newOrder.getDelivery().setCountry(deliveryCountry );
		newOrder.getBilling().setCountry(billingCountry );	
		
		if(billingZone!=null) {
			newOrder.getBilling().setZone(billingZone);
		}
		
		if(deliveryZone!=null) {
			newOrder.getDelivery().setZone(deliveryZone);
		}
		
		orderService.saveOrUpdate(newOrder);
		entityOrder.setOrder(newOrder);
		entityOrder.setBilling(newOrder.getBilling());
		entityOrder.setDelivery(newOrder.getDelivery());
		model.addAttribute("order", entityOrder);
		
		Long customerId = newOrder.getCustomerId();
		
		if(customerId!=null && customerId>0) {
			try {
				Customer customer = customerService.getById(customerId);
				if(customer!=null) {
					model.addAttribute("customer",customer);
				}
				
			} catch(Exception e) {
				LOGGER.error("Error while getting customer for customerId " + customerId, e);
			}
		
		}

		List<OrderProductDownload> orderProductDownloads = orderProdctDownloadService.getByOrderId(newOrder.getId());
		if(CollectionUtils.isNotEmpty(orderProductDownloads)) {
			model.addAttribute("downloads",orderProductDownloads);
		}
		
		
		/** 
		 * send email if admin posted orderHistoryComment
		 * 
		 * **/
		
		if(StringUtils.isBlank(entityOrder.getOrderHistoryComment())) {
		
			try {
				
				Customer customer = customerService.getById(newOrder.getCustomerId());
				Language lang = store.getDefaultLanguage();
				if(customer!=null) {
					lang = customer.getDefaultLanguage();
				}
				
				Locale customerLocale = LocaleUtils.getLocale(lang);

				StringBuilder customerName = new StringBuilder();
				customerName.append(newOrder.getBilling().getFirstName()).append(" ").append(newOrder.getBilling().getLastName());
				
				
				Map<String, String> templateTokens = EmailUtils.createEmailObjectsMap(request.getContextPath(), store, messages, customerLocale);
				templateTokens.put(EmailConstants.EMAIL_CUSTOMER_NAME, customerName.toString());
				templateTokens.put(EmailConstants.EMAIL_TEXT_ORDER_NUMBER, messages.getMessage("email.order.confirmation", new String[]{String.valueOf(newOrder.getId())}, customerLocale));
				templateTokens.put(EmailConstants.EMAIL_TEXT_DATE_ORDERED, messages.getMessage("email.order.ordered", new String[]{entityOrder.getDatePurchased()}, customerLocale));
				templateTokens.put(EmailConstants.EMAIL_TEXT_STATUS_COMMENTS, messages.getMessage("email.order.comments", new String[]{entityOrder.getOrderHistoryComment()}, customerLocale));
				templateTokens.put(EmailConstants.EMAIL_TEXT_DATE_UPDATED, messages.getMessage("email.order.updated", new String[]{DateUtils.formatDate(new Date())}, customerLocale));

				
				Email email = new Email();
				email.setFrom(store.getStorename());
				email.setFromEmail(store.getStoreEmailAddress());
				email.setSubject(messages.getMessage("email.order.status.title",new String[]{String.valueOf(newOrder.getId())},customerLocale));
				email.setTo(entityOrder.getOrder().getCustomerEmailAddress());
				email.setTemplateName(ORDER_STATUS_TMPL);
				email.setTemplateTokens(templateTokens);
	
	
				
				emailService.sendHtmlEmail(store, email);
			
			} catch (Exception e) {
				LOGGER.error("Cannot send email to customer",e);
			}
			
		}
		
		model.addAttribute("success","success");
		model.addAttribute("orderStatusList", Arrays.asList(OrderStatus.values()));
		model.addAttribute("paymentStatusList", Arrays.asList(PaymentStatus.values()));
		
		return "redirect:/admin/orders/editOrder.html?id="+newOrder.getId();
	}

	@PreAuthorize("hasRole('ORDER')")
	@RequestMapping(value="/admin/orders/create.html", method=RequestMethod.GET)
	public String createOrder(Model model, HttpServletRequest request, HttpServletResponse response) throws Exception {
		//display menu
		setMenu(model,request);
		//get all countries
		Language language = (Language)request.getAttribute("LANGUAGE");
		List<Country> countries = countryService.getCountries(language);
		model.addAttribute("orderStatusList", Arrays.asList(OrderStatus.values()));
		model.addAttribute("paymentStatusList", Arrays.asList(PaymentStatus.values()));
		model.addAttribute("countries", countries);
		com.salesmanager.web.admin.entity.orders.Order order = new com.salesmanager.web.admin.entity.orders.Order();
		model.addAttribute("order",order);
		return ControllerConstants.Tiles.Order.orderCreate;

	}
	
	@PreAuthorize("hasRole('ORDER')")
	@RequestMapping(value="/admin/orders/saveNew.html", method=RequestMethod.POST)
	public String saveNewOrder(@Valid @ModelAttribute("order") com.salesmanager.web.admin.entity.orders.Order entityOrder, BindingResult result, Model model, HttpServletRequest request, HttpServletResponse response, Locale locale) throws Exception {		
		Language language = (Language)request.getAttribute("LANGUAGE");
		List<Country> countries = countryService.getCountries(language);
		model.addAttribute("countries", countries);
		
		MerchantStore store = (MerchantStore)request.getAttribute(Constants.ADMIN_STORE);
		
		Set<OrderProduct> orderProducts = new HashSet<OrderProduct>();
		Set<OrderTotal> orderTotals = new HashSet<OrderTotal>();
		Set<OrderStatusHistory> orderHistory = new HashSet<OrderStatusHistory>();
		
		
		Date date = new Date();
		if(!StringUtils.isBlank(entityOrder.getDatePurchased() ) ){
			try {
				date = VN_DATE_FORMAT.parse(entityOrder.getDatePurchased());
			} catch (Exception e) {
				ObjectError error = new ObjectError("datePurchased",messages.getMessage("message.invalid.date", locale));
				result.addError(error);
			}
			
		} else {
			date = new Date(System.currentTimeMillis());
		}
		 

		if(!StringUtils.isBlank(entityOrder.getOrder().getCustomerEmailAddress() ) ){
			 java.util.regex.Matcher matcher = PATTERN.matcher(entityOrder.getOrder().getCustomerEmailAddress());
			 
			 if(!matcher.find()) {
				ObjectError error = new ObjectError("customerEmailAddress",messages.getMessage("Email.order.customerEmailAddress", locale));
				result.addError(error);
			 }
		}else{
			ObjectError error = new ObjectError("customerEmailAddress",messages.getMessage("NotEmpty.order.customerEmailAddress", locale));
			result.addError(error);
		}

		 
		if( StringUtils.isBlank(entityOrder.getOrder().getBilling().getFirstName() ) ){
			 ObjectError error = new ObjectError("billingFirstName", messages.getMessage("NotEmpty.order.billingFirstName", locale));
			 result.addError(error);
		}
		
		if( StringUtils.isBlank(entityOrder.getOrder().getBilling().getFirstName() ) ){
			 ObjectError error = new ObjectError("billingLastName", messages.getMessage("NotEmpty.order.billingLastName", locale));
			 result.addError(error);
		}
		
		/*
		if(OrderType.ORDER.equals(entityOrder.getOrder().getOrderType())){
			if( StringUtils.isBlank(entityOrder.getOrder().getBilling().getAddress() ) ){
				 ObjectError error = new ObjectError("billingAddress", messages.getMessage("NotEmpty.order.billingStreetAddress", locale));
				 result.addError(error);
			}
			 
			if( StringUtils.isBlank(entityOrder.getOrder().getBilling().getCity() ) ){
				 ObjectError error = new ObjectError("billingCity",messages.getMessage("NotEmpty.order.billingCity", locale));
				 result.addError(error);
			}
			 
			if( entityOrder.getOrder().getBilling().getZone()==null){
				if( StringUtils.isBlank(entityOrder.getOrder().getBilling().getState())){
					 ObjectError error = new ObjectError("billingState",messages.getMessage("NotEmpty.order.billingState", locale));
					 result.addError(error);
				}
			}
		}
		*/
		
		// handle products list
		String[] quantities = request.getParameterValues("quantityAdd");
		String productNames[] = request.getParameterValues("productNameAdd");
		boolean noProduct = false;
		if(quantities==null || productNames==null || quantities.length != productNames.length){
			 result.addError(new ObjectError("billingState", messages.getMessage("NotEmpty.order.product", locale)));
			 noProduct = true;
		}

		if(noProduct)
		{
			entityOrder.getOrder().setOrderProducts( orderProducts);
			entityOrder.getOrder().setOrderTotal(orderTotals);
			entityOrder.getOrder().setOrderHistory(orderHistory);
			model.addAttribute("countries", countries);
			model.addAttribute("orderStatusList", Arrays.asList(OrderStatus.values()));
			model.addAttribute("paymentStatusList", Arrays.asList(PaymentStatus.values()));
			model.addAttribute("order",entityOrder);
			return ControllerConstants.Tiles.Order.orderCreate;
		}
		
		// create new order entity ready to persist to database
		com.salesmanager.core.business.order.model.Order newOrder = new com.salesmanager.core.business.order.model.Order();
		newOrder.setCurrency(store.getCurrency());
		newOrder.setMerchant(store);
		
		// true if order finish
		boolean isUpdateQtt = OrderUtils.inUpdateQuantity(entityOrder.getOrder().getStatus());
		
		BigDecimal subTotal = BigDecimal.ZERO;
		
		for(int i = 0; i<productNames.length; i++){
			try{
				String productname = productNames[i];
				String quantityStr = quantities[i];
				int quantity = Integer.parseInt(quantityStr.trim());
				int idx = productname.lastIndexOf("-");
				if(idx != -1){
					String code = productname.substring(idx+1, productname.length()).trim();
					Product product = productService.getByCode(code, language);
					if(product==null) continue;
					
					OrderProduct op = new OrderProduct();
					op.setSku(product.getSku());
					op.setProductQuantity(quantity);
					ProductAvailability productAvail = product.getAvailabilities().iterator().next();
					if(isUpdateQtt){
						productAvail.setProductQuantity(productAvail.getProductQuantity() - quantity);
					} else {
						productAvail.setOrderReserveQuantity(productAvail.getOrderReserveQuantity() + quantity);
					}

					productAvailabilityService.update(productAvail);
					op.setOneTimeCharge(productAvail.defaultPrice().getProductPriceAmount());
					op.setProductName(product.getDescriptions().iterator().next().getName());
					op.setOrder(newOrder);
					
					BigDecimal quantityB = new BigDecimal(op.getProductQuantity());
					subTotal = subTotal.add(op.getOneTimeCharge().multiply(quantityB));

					orderProducts.add(op);	
				}
				
			} catch(Exception e){}			
		}
		

		if (result.hasErrors()) {
			entityOrder.getOrder().setOrderProducts( orderProducts);
			entityOrder.getOrder().setOrderTotal(orderTotals);
			entityOrder.getOrder().setOrderHistory(orderHistory);
			model.addAttribute("countries", countries);
			model.addAttribute("order",entityOrder);
			return ControllerConstants.Tiles.Order.orderCreate;
		}
		
		OrderTotal orderSubTotalEntry = new OrderTotal();
		orderSubTotalEntry.setOrderTotalCode("order.total.subtotal");
		orderSubTotalEntry.setValue(subTotal);
		orderSubTotalEntry.setText("order.total.subtotal");
		orderSubTotalEntry.setSortOrder(5);
		orderSubTotalEntry.setOrder(newOrder);
		orderTotals.add(orderSubTotalEntry);
		
		OrderTotal orderTotalEntry = new OrderTotal();
		orderTotalEntry.setOrderTotalCode("order.total.total");
		orderTotalEntry.setValue(subTotal);
		orderTotalEntry.setText("order.total.total");
		orderTotalEntry.setSortOrder(300);
		orderTotalEntry.setOrder(newOrder);
		orderTotals.add(orderTotalEntry);
		
		newOrder.setOrderTotal(orderTotals);
		newOrder.setTotal(subTotal);
		
		Country c = countryService.getByCode(COUNTRY_CODE_DEFAULT);
		entityOrder.getOrder().getBilling().setCountry(c);
		entityOrder.getOrder().getDelivery().setCountry(c);
		
		OrderStatus status = newOrder.getStatus();
		if(status==null) {
			status = OrderStatus.ORDERED;
			newOrder.setStatus(status);
		}
		Set<OrderStatusHistory> statusHistorySet = new HashSet<OrderStatusHistory>();
		OrderStatusHistory statusHistory = new OrderStatusHistory();
		statusHistory.setStatus(status);
		statusHistory.setDateAdded(new Date());
		statusHistory.setOrder(newOrder);
		statusHistorySet.add(statusHistory);
		newOrder.setOrderHistory(statusHistorySet);
		
		
				
		newOrder.setOrderProducts(orderProducts);
		newOrder.setCustomerEmailAddress(entityOrder.getOrder().getCustomerEmailAddress() );
		newOrder.setStatus(entityOrder.getOrder().getStatus() );
		newOrder.setPaymentStatus(entityOrder.getOrder().getPaymentStatus());
		

		Long custId = entityOrder.getOrder().getCustomerId();
		if (custId != null && custId > 0) {
			Customer customer = customerService.getById(custId);
			if (customer != null) {
				newOrder.setCustomerId(customer.getId());
			}
		} else {
			Customer newCustomer = new Customer();
			newCustomer.setMerchantStore(store);
			newCustomer.setEmailAddress(entityOrder.getOrder().getCustomerEmailAddress());		
			newCustomer.setDefaultLanguage(language);
			newCustomer.setBilling(entityOrder.getOrder().getBilling());
			newCustomer.setDelivery(entityOrder.getOrder().getDelivery());
						
			customerService.save(newCustomer);	
			newOrder.setCustomerId(newCustomer.getId());
		}
		
		newOrder.setDatePurchased(date);
		newOrder.setLastModified( new Date() );
		newOrder.setPaymentType(entityOrder.getOrder().getPaymentType());
		
		newOrder.setDelivery( entityOrder.getOrder().getDelivery() );
		newOrder.setBilling( entityOrder.getOrder().getBilling() );
		
		orderService.create(newOrder);
		orderService.flush();
		return "redirect:/admin/orders/editOrder.html?id="+newOrder.getId();
	}

	@SuppressWarnings("unchecked")
	@PreAuthorize("hasRole('ORDER')")
	@RequestMapping(value="/admin/orders/customerInfo.html", method=RequestMethod.GET, produces="application/json; charset=utf-8")
	public @ResponseBody String getCustomerInfo(HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		AjaxResponse resp = new AjaxResponse();
		
		String phone = request.getParameter("phone");
		String email = request.getParameter("email");
		boolean getByPhone = false;
		if(StringUtils.isNotEmpty(phone)){
			getByPhone = true;
		} else {
			if(StringUtils.isEmpty(email)){
				resp.setStatus(AjaxResponse.RESPONSE_STATUS_FAIURE);
				return resp.toJSONString();
			}
		}


		MerchantStore store = (MerchantStore)request.getAttribute(Constants.ADMIN_STORE);
		try {			
			List<Customer> customers;
			if(getByPhone)
				customers = customerService.getByTelephone(phone, store.getId());
			else
				customers = customerService.getByEmail(email, store.getId());

			if(customers==null) {
				resp.setStatus(AjaxResponse.RESPONSE_STATUS_FAIURE);
				return resp.toJSONString();
			}			
			
				
			for(Customer c : customers) {
				@SuppressWarnings("rawtypes")
				Map entry = new HashMap();
				entry.put("customerId", c.getId());
				if(getByPhone){
					entry.put("phone", phone);
				} else {
					entry.put("phone", getEmptyIfNull(c.getBilling().getTelephone()));
				}
				
				entry.put("email", c.getEmailAddress());
				
				entry.put("bfirstName", getEmptyIfNull(c.getBilling().getFirstName()));
				entry.put("blastName", getEmptyIfNull(c.getBilling().getLastName()));
				entry.put("bstreet", getEmptyIfNull(c.getBilling().getAddress()));
				entry.put("bState", getEmptyIfNull(c.getBilling().getState()));
				entry.put("bCity", getEmptyIfNull(c.getBilling().getCity()));
				
				if(c.getDelivery() != null){
					entry.put("dfirstName", getEmptyIfNull(c.getDelivery().getFirstName()));
					entry.put("dlastName", getEmptyIfNull(c.getDelivery().getLastName()));
					entry.put("dstreet", getEmptyIfNull(c.getDelivery().getAddress()));
					entry.put("dState", getEmptyIfNull(c.getDelivery().getState()));
					entry.put("dCity", getEmptyIfNull(c.getDelivery().getCity()));
				} else {
					entry.put("dfirstName", "");
					entry.put("dlastName", "");
					entry.put("dstreet", "");
					entry.put("dState", "");
					entry.put("dCity", "");	
				}
				resp.addDataEntry(entry);	
			}
			resp.setStatus(AjaxResponse.RESPONSE_OPERATION_COMPLETED);
			
		} catch(Exception e) {
			LOGGER.error("Cannot get customer for phone number " + phone, e);
			resp.setStatus(AjaxResponse.RESPONSE_STATUS_FAIURE);
			resp.setErrorMessage(e);
		}
		
		return resp.toJSONString();
	}

	
	@SuppressWarnings("unchecked")
	@PreAuthorize("hasRole('ORDER')")
	@RequestMapping(value="/admin/orders/productInfo.html", method=RequestMethod.GET, produces = "application/json; charset=utf-8")
	public @ResponseBody String getProductNameSKU(HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		AjaxResponse resp = new AjaxResponse();

		MerchantStore store = (MerchantStore)request.getAttribute(Constants.ADMIN_STORE);
		final String param = request.getParameter("term");
		
/*		
		List<Map> cache = (List<Map>)request.getSession().getAttribute(Constants.PRODUCT_NAME_SKU);
		if (cache != null) {
			boolean found = false;
			for(Map entry: cache){
				String value = ((String) entry.get("desc")).toLowerCase();
				if(value.contains(param)){
					resp.addDataEntry(entry);
					found = true;
				}
			}
			
			if(!found){
				resp.setStatus(AjaxResponse.RESPONSE_STATUS_FAIURE);
				return null;
			} else {
				resp.setStatus(AjaxResponse.RESPONSE_OPERATION_COMPLETED);
				return resp.toJSONString();
			}
		}
*/		
		try {			
			List<Product> products = productService.listProductNameByStore(store);
			
			if(products==null) {
				resp.setStatus(AjaxResponse.RESPONSE_STATUS_FAIURE);
				return null;
			}
			
			List<Map> mapEntries = new ArrayList<Map>();
			for(Product p : products) {
				@SuppressWarnings("rawtypes")
				Map entry = new HashMap();
				//String key = String.valueOf(p.getId());
				
				String price="";
				//String importPrice="";
				Iterator<ProductPrice> iterPrice = p.getAvailabilities().iterator().next().getPrices().iterator();
				while(iterPrice.hasNext()){
					ProductPrice priceEle = iterPrice.next();
					if(priceEle.isDefaultPrice()){
						price = String.valueOf(priceEle.getProductPriceAmount().longValue());
					} else {
						//importPrice = String.valueOf(priceEle.getProductPriceAmount().doubleValue());
					}
				}
				
				//entry.put("key", key);
				entry.put("price", price);
				String sku = p.getSku();
				//entry.put("value", sku);
				
				Set<ProductDescription> desc = p.getDescriptions();
				Iterator<ProductDescription> iter = desc.iterator();
				while(iter.hasNext()){
					ProductDescription pdesc = iter.next();
					if(sku.toLowerCase().contains(param) || pdesc.getName().toLowerCase().contains(param)){
						entry.put("desc", pdesc.getName() + " - " + sku);
						mapEntries.add(entry);
						resp.addDataEntry(entry);						
					} else {
						entry.put("desc", pdesc.getName() + " - " + sku);
						mapEntries.add(entry);
					}
					break;
				}					
			}
			//request.getSession().setAttribute(Constants.PRODUCT_NAME_SKU, mapEntries);
			resp.setStatus(AjaxResponse.RESPONSE_OPERATION_COMPLETED);
			
		} catch(Exception e) {
			resp.setStatus(AjaxResponse.RESPONSE_STATUS_FAIURE);
			resp.setErrorMessage(e);
		}
		
		return resp.toJSONString();
	}
	
	private void setMenu(Model model, HttpServletRequest request) throws Exception {
	
		//display menu
		Map<String,String> activeMenus = new HashMap<String,String>();
		activeMenus.put("order", "order");
		activeMenus.put("order-list", "order-list");
		
		@SuppressWarnings("unchecked")
		Map<String, Menu> menus = (Map<String, Menu>)request.getAttribute("MENUMAP");

		model.addAttribute("activeMenus",activeMenus);
		
		Menu currentMenu = (Menu)menus.get("order");
		model.addAttribute("currentMenu",currentMenu);
		model.addAttribute("activeMenus",activeMenus);
		//
		
	}

	private String getEmptyIfNull(String input){
		return StringUtils.isEmpty(input) ? "" : input;
	}
	
	private void updateQuantity(Set<OrderProduct> orderProducts, int action, Language language){
		Iterator<OrderProduct> products = orderProducts.iterator();
		while(products.hasNext()){
			OrderProduct next = products.next();
			Product product = productService.getByCode(next.getSku(), language);
			if(product != null){
				int quantity = next.getProductQuantity();
				ProductAvailability productAvail = product.getAvailabilities().iterator().next();
				if(action == OrderUtils.INCREASE_QUANTITY){
					productAvail.setOrderReserveQuantity(productAvail
							.getOrderReserveQuantity() + quantity);
					productAvail.setProductQuantity(productAvail
							.getProductQuantity() + quantity);
				} else if ( action == OrderUtils.DECREASE_QUANTITY){
					productAvail.setOrderReserveQuantity(productAvail
							.getOrderReserveQuantity() - quantity);
					productAvail.setProductQuantity(productAvail
							.getProductQuantity() - quantity);
				}
				try {
					productAvailabilityService.update(productAvail);
				} catch (ServiceException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
	
	private void updateImportQuantity(Set<OrderProduct> orderProducts, int action, Language language){
		Iterator<OrderProduct> products = orderProducts.iterator();
		while(products.hasNext()){
			OrderProduct next = products.next();
			Product product = productService.getByCode(next.getSku(), language);
			if(product != null){
				int quantity = next.getProductQuantity();
				ProductAvailability productAvail = product.getAvailabilities().iterator().next();
				if(action == OrderUtils.INCREASE_QUANTITY){
					productAvail.setImportReserveQuantity(productAvail
							.getImportReserveQuantity() - quantity);
					productAvail.setProductQuantity(productAvail
							.getProductQuantity() + quantity);
				} else if ( action == OrderUtils.DECREASE_QUANTITY){
					productAvail.setImportReserveQuantity(productAvail
							.getImportReserveQuantity() + quantity);
					productAvail.setProductQuantity(productAvail
							.getProductQuantity() - quantity);
				}
				try {
					productAvailabilityService.update(productAvail);
				} catch (ServiceException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}
